#include "spk_camera.h"
#include "config.h"
#include "utils.h"
#include "sip_client.h"
#include "rtp_send_ps.h"

#define LOG_TAG "sip_client"
#define LOG_LVL LOG_LVL_INFO
#include "spk_ulog.h"

cls_sip_client::cls_sip_client(cls_spkcam *p_app)
{
    app = p_app;
    cfg_src = app->cfg_src;
    cfg_cur = app->cfg_cur;

    mRegistered = false;

    sendps = nullptr;

    init_sip_conf();
}

cls_sip_client::~cls_sip_client()
{
    if (sendps)
    {
        sendps->sendps_loop_stop();
        delete sendps;
        sendps = nullptr;
    }
    
    sip_client_loop_stop();
}

void cls_sip_client::sip_client_main_loop()
{
    if (init_sip_client() != 0)
    {
        return;
    }

    LOG_I("IN loop()");

    bool allowReg = true;

    int64_t lastKeepaliveTimestamp = 0;
    int64_t curTimestamp = 0;
    int64_t interval = 60000; // 客户端发送keepalive检测的间隔，单位：毫秒

    while (sip_client_running)
    {

        // 首次发起注册
        if (allowReg && !mRegistered)
        {
            allowReg = false;
            request_register();
            // LOGI("first connect");
        }

        // 心跳机制 start （开发过程中，为防止影响抓包，可以先注释）
        if (mRegistered)
        {
            curTimestamp = getCurTimestamp();
            if (lastKeepaliveTimestamp == 0)
            {
                lastKeepaliveTimestamp = curTimestamp;
            }
            else
            {
                if ((curTimestamp - lastKeepaliveTimestamp) > interval)
                {
                    request_message_keepalive();
                    lastKeepaliveTimestamp = curTimestamp;
                }
            }
        }
        // 心跳机制 end

        // eXosip_event_t* evtp = eXosip_event_wait(sipClient->mSipCtx, 0, 20);
        eXosip_event_t *evtp = eXosip_event_wait(mSipCtx, 0, 100);
        if (!evtp)
        {
            eXosip_automatic_action(mSipCtx);
            osip_usleep(100000);
            // osip_usleep(10000);
            continue;
        }
        eXosip_automatic_action(mSipCtx);
        sip_event_handle(evtp);
        eXosip_event_free(evtp); // 释放
    }
}

void cls_sip_client::sip_client_loop_start()
{
    sip_client_running = true;

    main_loop_thread = std::make_unique<std::thread>([this]()
                                                     {
                                                         sip_client_main_loop(); // 直接调用非静态成员函数
                                                     });
}

void cls_sip_client::sip_client_loop_stop()
{
    sip_client_running = false;

    if (main_loop_thread && main_loop_thread->joinable())
    {
        main_loop_thread->join();
    }
}

void cls_sip_client::init_sip_conf()
{
    strncpy(sip_config.ua, "ckkj", sizeof(sip_config.ua) - 1);
    strncpy(sip_config.device_name, (const char *)cfg_cur->device_name, sizeof(sip_config.device_name) - 1);
    strncpy(sip_config.channle_name, "channel_name", sizeof(sip_config.channle_name) - 1);
    strncpy(sip_config.password, (const char *)cfg_cur->sip_password, sizeof(sip_config.password) - 1);
    sip_config.sip_register_timeout_second = cfg_cur->sip_register_timeout_second;

    sip_config.local_ip = ip_addr_trans(cfg_cur->ip_addr);
    sip_config.local_sip_port = cfg_cur->sip_local_port;
    strncpy(sip_config.local_sip_user_id, (const char *)cfg_cur->sip_user_id, sizeof(sip_config.local_sip_user_id) - 1);
    sip_config.local_rtp_port = 10011;

    sip_config.server_ip = ip_addr_trans(cfg_cur->sip_server_ip_addr);
    sip_config.server_sip_port = cfg_cur->sip_server_port;
    strncpy(sip_config.server_sip_id, (const char *)cfg_cur->sip_server_id, sizeof(sip_config.server_sip_id) - 1);
    strncpy(sip_config.server_domain, (const char *)cfg_cur->sip_server_domain, sizeof(sip_config.server_domain) - 1);
}

int cls_sip_client::init_sip_client()
{
    LOG_D("IN init_sip_client");

    mSipCtx = eXosip_malloc();
    if (!mSipCtx)
    {
        LOG_E("new uas context error");
        return -1;
    }
    if (eXosip_init(mSipCtx))
    {
        LOG_E("exosip init error");
        return -1;
    }
    if (eXosip_listen_addr(mSipCtx, IPPROTO_TCP, NULL, sip_config.local_sip_port, AF_INET, 0))
    {
        // if (eXosip_listen_addr(mSipCtx, IPPROTO_UDP, NULL, mClientConfig->port, AF_INET, 0)) {
        LOG_E("listen error");
        return -1;
    }
    eXosip_set_user_agent(mSipCtx, sip_config.ua);
    if (eXosip_add_authentication_info(mSipCtx, (const char *)sip_config.local_sip_user_id, (const char *)sip_config.local_sip_user_id, (const char *)sip_config.password, NULL, NULL) < 0)
    {
        LOG_E("eXosip_add_authentication_info error");
        return -1;
    }

    return 0;
}

int cls_sip_client::sip_event_handle(eXosip_event_t *evtp)
{
    switch (evtp->type)
    {
    case EXOSIP_MESSAGE_NEW:
        LOG_I("EXOSIP_MESSAGE_NEW");

        if (MSG_IS_REGISTER(evtp->request))
        {
            LOG_I("MSG_IS_REGISTER，不应该出现的响应，请排查问题");
        }
        else if (MSG_IS_MESSAGE(evtp->request))
        {
            this->response_message(evtp);
        }
        else
        {
            LOG_I("未定义类型的MESSAGE");

            this->dump_request(evtp);

            /*
                    // 可能会出现的请求
                    BYE sip:00662800000403000001@192.168.8.200:5060 SIP/2.0
                    Via: SIP/2.0/UDP 192.168.8.114:5060;branch=z9hG4bK695c5ff8b5c014866ffc6a554c242a6d
                    From: <sip:00662800000401000001@0066280000>;tag=185326220
                    To: <sip:00662802002006028104@0066280000>;tag=2009556327
                    Call-ID: 05a7fc88c30878338ff311a788e9cefa@192.168.8.114
                    CSeq: 185 BYE
                    Max-forwards: 70
                    Content-Length: 0
                    */
        }
        break;
    case EXOSIP_CALL_ANSWERED:
        LOG_I("EXOSIP_CALL_ANSWERED type=%d:这里应该主动发送ACK之后的回复", evtp->type);
        this->dump_request(evtp);
        this->dump_response(evtp);
        break;
    case EXOSIP_REGISTRATION_FAILURE:
        LOG_I("EXOSIP_REGISTRATION_FAILURE type=%d", evtp->type);
        LOG_I("mRegistered=%d,mRegisterId=%d", mRegistered, mRegisterId);
        this->mRegistered = false;

        if (eXosip_add_authentication_info(mSipCtx, (const char *)sip_config.local_sip_user_id, (const char *)sip_config.local_sip_user_id, (const char *)sip_config.password, NULL, NULL) < 0)
        {
            LOG_I("eXosip_add_authentication_info error");
        }
        break;
    case EXOSIP_REGISTRATION_SUCCESS:
        LOG_I("EXOSIP_REGISTRATION_SUCCESS type=%d", evtp->type);
        this->mRegistered = true;
        LOG_I("mRegistered=%d,mRegisterId=%d", mRegistered, mRegisterId);

        //                this->dump_request(evtp);
        //                this->request_message_keepalive();
        break;
    case EXOSIP_CALL_INVITE:
        LOG_I("EXOSIP_CALL_INVITE type=%d: 接收到对方发送了Invite请求", evtp->type);
        //                this->dump_request(evtp);
        //                this->dump_response(evtp);
        this->response_invite(evtp);
        break;
    case EXOSIP_CALL_ACK:
        LOG_I("EXOSIP_CALL_ACK type=%d: 收到来自对方ACK请求。准备国标推流。", evtp->type);
        dump_request(evtp);
        this->response_ack(evtp);
        break;
    case EXOSIP_IN_SUBSCRIPTION_NEW:
        LOG_I("EXOSIP_IN_SUBSCRIPTION_NEW type=%d", evtp->type);
        dump_request(evtp);
        break;
    case EXOSIP_CALL_NOANSWER:
    {
        LOG_I("EXOSIP_IN_SUBSCRIPTION_NEW type=%d", evtp->type);
        break;
    }
    case EXOSIP_CALL_MESSAGE_NEW: // 14
    {
        LOG_I("EXOSIP_CALL_MESSAGE_NEW type=%d", evtp->type);
        this->dump_request(evtp);
        this->dump_response(evtp);
        break;
    }
    case EXOSIP_CALL_CLOSED: // 21
    {
        LOG_I("EXOSIP_CALL_CLOSED type=%d", evtp->type);
        this->dump_request(evtp);
        this->dump_response(evtp);
        this->response_bye(evtp);
        break;
    }
    case EXOSIP_CALL_RELEASED: // 22
    {
        LOG_I("EXOSIP_CALL_RELEASED type=%d: Bye确认", evtp->type);
        break;
    }
    case EXOSIP_MESSAGE_REQUESTFAILURE:
        LOG_I("EXOSIP_MESSAGE_REQUESTFAILURE type=%d", evtp->type);
        LOG_I("evtp->textinfo= '%s' ", evtp->textinfo);
        if (evtp->ack)
        {
            char *ack_str;
            size_t ack_str_len;
            osip_message_to_str(evtp->ack, &ack_str, &ack_str_len);
            LOG_I("ack_str=%s", ack_str);
        }
        this->dump_request(evtp);
        this->dump_response(evtp);

        break;
    case EXOSIP_MESSAGE_ANSWERED:
        // LOGI("EXOSIP_MESSAGE_ANSWERED type=%d: 接收到来自对应的MESSAGE请求。", evtp->type);
        break;
    default:
        LOG_I("type=%d unknown ", evtp->type);
        break;
    }

    return 0;
}

int cls_sip_client::response_message_answer(eXosip_event_t *evtp, int code)
{
    osip_message_t *msg = nullptr;
    int returnCode = eXosip_message_build_answer(mSipCtx, evtp->tid, code, &msg);

    if (returnCode == 0 && msg)
    {
        eXosip_lock(mSipCtx);
        eXosip_message_send_answer(mSipCtx, evtp->tid, code, msg);
        eXosip_unlock(mSipCtx);
        //        osip_message_free(msg);
    }
    else
    {
        bool msg_state = false;
        if (msg)
        {
            msg_state = true;
        }
        LOG_E("error: code=%d,returnCode=%d,msg=%d", code, returnCode, msg_state);
    }
    return 0;
}

int cls_sip_client::response_message(eXosip_event_t *evtp)
{
    osip_body_t *req_body = nullptr;
    osip_message_get_body(evtp->request, 0, &req_body);
    //        LOGI("req_body->body: %s", req_body->body);

    char cmd[64] = {0};
    parse_xml(req_body->body, "<CmdType>", false, "</CmdType>", false, cmd);
    LOG_I("got message: %s", cmd);

    char SN_c[20] = {0};              // 序列号
    int SN = 0;                       // 序列号
    char DeviceID[100] = {0};         // 设备编码
    char DecoderChannelID[100] = {0}; // 解码器通道编码
    char PlayUrl[512] = {0};          // 源视频地址

    parse_xml(req_body->body, "<SN>", false, "</SN>", false, SN_c);
    parse_xml(req_body->body, "<DeviceID>", false, "</DeviceID>", false, DeviceID);
    parse_xml(req_body->body, "<DecoderChannelID>", false, "</DecoderChannelID>", false, DecoderChannelID);
    parse_xml(req_body->body, "<PlayUrl>", false, "</PlayUrl>", false, PlayUrl);

    LOG_I("DeviceID:%s", DeviceID);
    LOG_I("DecoderChannelID:%s", DecoderChannelID);
    SN = std::stoi(SN_c);

    if (!strcmp(cmd, "Catalog"))
    { // cmd == Catalog
        LOG_I("cmd == Catalog");
        this->response_message_answer(evtp, 200);
        // osip_usleep(100000);
        request_message_catalog(SN);
    }
    else if (!strcmp(cmd, "DeviceInfo"))
    {
        LOG_I("cmd == DeviceInfo");
        this->response_message_answer(evtp, 200);
        response_message_deviceinfo(SN);
    }
    else
    {
        this->response_message_answer(evtp, 200);
    }

    return 0;
}

int cls_sip_client::response_invite(eXosip_event_t *evtp)
{
    char *username = evtp->request->to->url->username; // 对应摄像头的DeviceID
    char *CallID = evtp->request->call_id->number;
    LOG_I("username:%s", username);
    LOG_I("CallID:%s", CallID);

    osip_message_t *answer = nullptr;
    eXosip_lock(mSipCtx);
    eXosip_call_send_answer(mSipCtx, evtp->tid, 180, nullptr);
    int ret = eXosip_call_build_answer(mSipCtx, evtp->tid, 200, &answer);
    if (ret != 0)
    {
        eXosip_call_send_answer(mSipCtx, evtp->tid, 400, nullptr);
        LOG_E("camera: %s eXosip_call_build_answer error", username);
    }
    else
    {

        // 采用exosip的函数解析sdp
        /*
               printf("-----------exosip parse start-----------\n");
               sdp_message_t *remote_sdp = eXosip_get_remote_sdp(mSipCtx, evtp->did);
               if(remote_sdp){
               sdp_media_t *video_sdp = eXosip_get_video_media(remote_sdp);
               if (video_sdp) {
               int pos = 0;
               char *video_port = video_sdp->m_port; // audio_port
               for (int i = 0; i < video_sdp->a_attributes.nb_elt; i++)
               {
               sdp_attribute_t *attr = (sdp_attribute_t *)osip_list_get(&video_sdp->a_attributes, i);
               printf("1-%s : %s\n", attr->a_att_field, attr->a_att_value);
               }
               while (!osip_list_eol(&(remote_sdp->a_attributes), pos)) {
               sdp_attribute_t *at;
               at = (sdp_attribute_t *)osip_list_get(&remote_sdp->a_attributes, pos);
               printf(
               "2-%s : %s\n", at->a_att_field,
               at->a_att_value); // 这里解释了为什么在SDP消息体中属性a里面存放必须是两列
               pos++;
               }
               while (!osip_list_eol(&(remote_sdp->m_medias), pos)) {
               sdp_attribute_t *at;

               at = (sdp_attribute_t *)osip_list_get(&remote_sdp->m_medias, pos);
               printf(
               "3-%s : %s\n", at->a_att_field,
               at->a_att_value); // 这里解释了为什么在SDP消息体中属性a里面存放必须是两列

               pos++;
               }
               }
               }
               printf("-----------exosip parse end-----------\n");
               */

        printf("-----------my parse start-----------\n");
        int trackSize = 0;
        unsigned int ssrc = 0;
        ctx_sdp_track track;
        // 下面解析SDP的方式只适合一个媒体流，所有如果同时包含音频和视频流，需要注意！！！
        // 采用自定义的方式解析sdp
        osip_body_t *req_body = nullptr;
        osip_message_get_body(evtp->request, 0, &req_body);

        std::vector<std::string> lineArray = split(req_body->body, "\n");
        for (auto &line : lineArray)
        {
            printf(">>>>>>%s\n", line.data());

            if (!strncmp(line.data(), "c=IN", strlen("c=IN")))
            {
                // example: c=IN IP4 192.168.8.91
                if (sscanf(line.data(), "c=IN IP4 %s ", &track.peerIp) != 1)
                {
                    LOG_E("parse line error:%s", line.data());
                    break;
                }
            }
            if (!strncmp(line.data(), "m=", strlen("m=")))
            {
                // example: m=video 15060 TCP/RTP/AVP 96
                if (sscanf(line.data(), "m=%s %d %s %s ", &track.mediaType, &track.peerRtpPort, &track.peerRtpTransport, &track.peerStreamType) != 4)
                {
                    LOG_E("parse line error:%s", line.data());
                    break;
                }

                // set the info about remote port
                sip_config.server_rtp_port = track.peerRtpPort;
            }
            if (!strncmp(line.data(), "y=", strlen("y=")))
            {
                if (sscanf(line.data(), "y=%d", &ssrc) != 1)
                {
                    LOG_E("parse line error:%s", line.data());
                    break;
                }
                else
                {
                    // success
                    trackSize++;
                }

                // set the info about ssrc
                sip_config.ssrc = ssrc;
            }
        }
        printf("-----------my parse end-----------\n");

        // while(1);

        LOG_I("trackSize=%d", trackSize);

        // 还有一点需要注意，这个设置：a=sendonly
        char sdpBuf[2048];
        /* snprintf( */
        /*         sdpBuf, sizeof(sdpBuf), */
        /*         "v=0\r\n" */
        /*         "o=admin %d 1 IN IP4 %s\r\n" */
        /*         "s=Play\r\n" */
        /*         "c=IN IP4 %s\r\n" */
        /*         "t=0 0\r\n" */
        /*         "m=video %d RTP/AVP 96 98 97\r\n" */
        /*         "a=sendonly\r\n" */
        /*         "a=rtpmap:96 PS/90000\r\n" */
        /*         "a=rtpmap:98 H264/90000\r\n" */
        /*         "a=rptmap:97 MPEG4/90000\r\n", */
        /*         genRandomInt(), */
        /*         mServerConfig->getIp(), mClientConfig->ip, */
        /*         mClientConfig->localRtpPort); */

        // std::string client_ip =  ip_addr_trans(m_info->ip_addr);
        // std::string server_ip =  ip_addr_trans(m_info->sip_server_ip_addr);

        snprintf(
            sdpBuf, sizeof(sdpBuf),
            "v=0\r\n"
            "o=%s %d 0 IN IP4 %s\r\n"
            "s=Play\r\n"
            "c=IN IP4 %s\r\n"
            "t=0 0\r\n"
            /*"m=video %d RTP/AVP 96 98 97\r\n"*/
            "m=video %d TCP/RTP/AVP 96\r\n"
            "a=setup:active\r\n"
            "a=sendonly\r\n"
            "a=rtpmap:96 PS/90000\r\n"
            "a=filesize:0\r\n"
            "y=%010d\n",
            /* "a=rtpmap:98 H264/90000\r\n" */
            /* "a=rptmap:97 MPEG4/90000\r\n", */
            sip_config.local_sip_user_id,
            0,
            /* genRandomInt(), */
            sip_config.server_ip.c_str(),
            sip_config.server_ip.c_str(),
            sip_config.local_rtp_port,
            sip_config.ssrc);

        osip_message_set_body(answer, sdpBuf, strlen(sdpBuf));
        osip_message_set_content_type(answer, "application/sdp");
        eXosip_call_send_answer(mSipCtx, evtp->tid, 200, answer);
    }
    eXosip_unlock(mSipCtx);

    return 0;
}

int cls_sip_client::response_ack(eXosip_event_t *evtp)
{
    char *username = evtp->request->to->url->username; // 对应摄像头的DeviceID
    char *CallID = evtp->request->call_id->number;
    LOG_I("接收到信令服务的ACK，开始ps over rtp 推流");
    LOG_I("username:%s\n", username);
    LOG_I("CallID:%s\n", CallID);

    /***
     *_______________#########_______________________
     *______________############_____________________
     *______________#############____________________
     *_____________##__###########___________________
     *____________###__######_#####__________________
     *____________###_#######___####_________________
     *___________###__##########_####________________
     *__________####__###########_####_______________
     *________#####___###########__#####_____________
     *_______######___###_########___#####___________
     *_______#####___###___########___######_________
     *______######___###__###########___######_______
     *_____######___####_##############__######______
     *____#######__#####################_#######_____
     *____#######__##############################____
     *___#######__######_#################_#######___
     *___#######__######_######_#########___######___
     *___#######____##__######___######_____######___
     *___#######________######____#####_____#####____
     *____######________#####_____#####_____####_____
     *_____#####________####______#####_____###______
     *______#####______;###________###______#________
     *________##_______####________####______________
     */

    // 正式开始推流
    sendps = new cls_rtp_send_ps(this);
    sendps->sendps_loop_start();

    return 0;
}

int cls_sip_client::response_bye(eXosip_event_t *evtp)
{
    char *username = evtp->request->to->url->username; // 对应摄像头的DeviceID
    char *CallID = evtp->request->call_id->number;
    LOG_I("接收到信令服务的BYE，停止ps over rtp 推流");
    LOG_I("username:%s", username);
    LOG_I("CallID:%s", CallID);
    // 停止推流
    if (sendps)
    {
        sendps->sendps_loop_stop();
        delete sendps;
        sendps = nullptr;
    }

    return 0;
}

int cls_sip_client::request_register()
{
    int ret = -1;
    osip_message_t *msg = NULL;
    char from[1024] = {0};
    char contact[1024] = {0};
    char proxy[1024] = {0};

    if (mRegistered)
    { // refresh register
        LOG_I("刷新注册 mRegisterId=%d", mRegisterId);

        ret = eXosip_register_build_register(mSipCtx, mRegisterId, sip_config.sip_register_timeout_second, &msg);
        if (!ret)
        {
            LOG_E("eXosip_register_build_register error: ret=%d", ret);
            return -1;
        }
    }
    else
    { // new register
        LOG_I("未注册 mRegisterId=%d", mRegisterId);

        sprintf(from, "sip:%s@%s:%d", sip_config.local_sip_user_id, sip_config.local_ip.c_str(), sip_config.local_sip_port);
        sprintf(proxy, "sip:%s@%s:%d", sip_config.server_sip_id, sip_config.server_ip.c_str(), sip_config.server_sip_port);
        sprintf(contact, "sip:%s@%s:%d", sip_config.local_sip_user_id, sip_config.local_ip.c_str(), sip_config.local_sip_port);

        mRegisterId = eXosip_register_build_initial_register(mSipCtx, from, proxy, contact, sip_config.sip_register_timeout_second, &msg);
        if (mRegisterId <= 0)
        {
            LOG_E("eXosip_register_build_initial_register error: mRegisterId=%d", mRegisterId);
            return -1;
        }
    }
    ret = eXosip_register_send_register(mSipCtx, mRegisterId, msg);
    if (ret)
    {
        LOG_E("eXosip_register_send_register error: ret=%d", ret);
        return ret;
    }

    char *msg_str;
    size_t msg_strlen;
    osip_message_to_str(msg, &msg_str, &msg_strlen);
    LOG_I("注册请求体: %s", msg_str);
    return ret;
}

int cls_sip_client::request_message_keepalive()
{
    char from[1024] = {0};
    char to[1024] = {0};

    sprintf(from, "sip:%s@%s:%d", sip_config.local_sip_user_id, sip_config.local_ip.c_str(), sip_config.local_sip_port);
    sprintf(to, "sip:%s@%s:%d", sip_config.server_sip_id, sip_config.server_ip.c_str(), sip_config.server_sip_port);

    osip_message_t *msg;
    char body[1024] = {0};

    sprintf(
        body,
        "<?xml version=\"1.0\" encoding=\"GB2312\" standalone=\"yes\" ?>\r\n"
        "<Notify>\r\n"
        "<CmdType>Keepalive</CmdType>\r\n"
        "<SN>1</SN>\r\n"
        "<DeviceID>%s</DeviceID>\r\n"
        "<Status>OK</Status>\r\n"
        "</Notify>\r\n",
        sip_config.local_sip_user_id);

    eXosip_message_build_request(mSipCtx, &msg, "MESSAGE", to, from, NULL);
    osip_message_set_body(msg, body, strlen(body));
    osip_message_set_content_type(msg, "Application/MANSCDP+xml");
    eXosip_message_send_request(mSipCtx, msg);

    return 0;
}

int cls_sip_client::request_message_catalog(int sn)
{
    char from[1024] = {0};
    char to[1024] = {0};

    // sprintf(from, "sip:%s@%s:%d", mClientConfig->id, mClientConfig->ip, mClientConfig->port);
    // sprintf(to, "sip:%s@%s:%d", mServerConfig->getSipId(), mServerConfig->getIp(), mServerConfig->getPort());

    // std::string client_ip =  ip_addr_trans(m_info->ip_addr);
    // std::string server_ip =  ip_addr_trans(m_info->sip_server_ip_addr);

    sprintf(from, "sip:%s@%s:%d", sip_config.local_sip_user_id, sip_config.local_ip.c_str(), sip_config.local_sip_port);
    sprintf(to, "sip:%s@%s:%d", sip_config.server_sip_id, sip_config.server_ip.c_str(), sip_config.server_sip_port);

    osip_message_t *msg;
    char body[1024] = {0};
    char *s;
    size_t len;

    /* sprintf( */
    /*         body, */
    /*         "<?xml version=\"1.0\"?>\r\n" */
    /*         "<Query>\r\n" */
    /*         "<CmdType>Catalog</CmdType>\r\n" */
    /*         "<SN>1</SN>\r\n" */
    /*         "<DeviceID>%s</DeviceID>\r\n" */
    /*         "</Query>\r\n", */
    /*         // mServerConfig->getSipId());
        /*         mClientConfig->id); */
    sprintf(
        body,
        "<?xml version=\"1.0\" encoding=\"GB2312\"?>\n"
        "<Response>\n"
        "<CmdType>Catalog</CmdType>\n"
        "<SN>%d</SN>\n"
        "<DeviceID>%s</DeviceID>\n"
        "<SumNum>1</SumNum>\n"
        "<DeviceList Num=\"1\">\n"
        "<Item>\n"
        "<DeviceID>%s</DeviceID>\r\n"
        "<Name>%s</Name>\n"
        "<Manufacturer>%s</Manufacturer>\n"
        "<Model>Model name</Model>\n"
        "<Owner>Owner name</Owner>\n"
        "<CivilCode>%s</CivilCode>\n"
        /*"<Block>Block 1</Block>\n"*/
        "<Address>wuhan</Address>\n"
        "<Parental>0</Parental>\n"
        "<ParentID>%s</ParentID>\n"
        "<SafetyWay>0</SafetyWay>\n"
        "<RegisterWay>1</RegisterWay>\n"
        /*"<CertNum>1</CertNum>\n"
                "<Certifiable>0</Certifiable>\n"
                "<ErrCode>0</ErrCode>\n"
                "<EndTime>2030-11-11T00:00:00:00</EndTime>\n"*/
        "<Secrecy>0</Secrecy>\n"
        /*"<IPAddress></IPAddress>\n"
                "<Port>5060</Port>\n"
                "<Password></Password>\n"*/
        "<Status>ON</Status>\n"
        /*"<Longitude></Longitude>\n"
                "<Latitude></Latitude>\n"*/
        "</Item>\n"
        "</DeviceList>\n"
        "</Response>\n",
        /* mServerConfig->getSipId()); */

        sn,
        sip_config.local_sip_user_id,
        sip_config.local_sip_user_id,
        sip_config.channle_name,
        sip_config.ua,
        sip_config.server_domain,

        sip_config.local_sip_user_id);

    eXosip_message_build_request(mSipCtx, &msg, "MESSAGE", to, from, NULL);
    osip_message_set_body(msg, body, strlen(body));
    osip_message_set_content_type(msg, "Application/MANSCDP+xml");
    eXosip_message_send_request(mSipCtx, msg);

    osip_message_to_str(msg, &s, &len);
    LOG_I("send cmd DeviceInfo: \n%s", s);

    return 0;
}

int cls_sip_client::response_message_deviceinfo(int sn)
{
    char from[1024] = {0};
    char to[1024] = {0};

    // sprintf(from, "sip:%s@%s:%d", mClientConfig->id, mClientConfig->ip, mClientConfig->port);
    // sprintf(to, "sip:%s@%s:%d", mServerConfig->getSipId(), mServerConfig->getIp(), mServerConfig->getPort());

    // std::string client_ip =  ip_addr_trans(m_info->ip_addr);
    // std::string server_ip =  ip_addr_trans(m_info->sip_server_ip_addr);

    sprintf(from, "sip:%s@%s:%d", sip_config.local_sip_user_id, sip_config.local_ip.c_str(), sip_config.local_sip_port);
    sprintf(to, "sip:%s@%s:%d", sip_config.server_sip_id, sip_config.server_ip.c_str(), sip_config.server_sip_port);

    osip_message_t *msg;
    char body[1024] = {0};
    char *s;
    size_t len;

    sprintf(
        body,
        "<?xml version=\"1.0\" encoding=\"GB2312\"?>\n"
        "<Response>\n"
        "<CmdType>DeviceInfo</CmdType>\n"
        "<SN>%d</SN>\n"
        "<DeviceID>%s</DeviceID>\n"
        "<Result>OK</Result>\n"
        /*"<DeviceType>NVR</DeviceType>\n"*/
        "<DeviceName>%s</DeviceName>\n"
        "<Manufacturer>%s</Manufacturer>\n"
        "<Model>Mode Name</Model>\n"
        "<Firmware>TM-2808AN-HD</Firmware>\n"
        /*"<MaxCamera>1</MaxCamera>\n"
                "<MaxAlarm>1</MaxAlarm>\n"*/
        "<Channel>1</Channel>\n"
        "</Response>\n",

        /* mServerConfig->getSipId()); */
        sn,
        sip_config.local_sip_user_id,
        sip_config.device_name,
        sip_config.ua);

    eXosip_message_build_request(mSipCtx, &msg, "MESSAGE", to, from, NULL);
    osip_message_set_body(msg, body, strlen(body));
    osip_message_set_content_type(msg, "Application/MANSCDP+xml");
    eXosip_message_send_request(mSipCtx, msg);

    osip_message_to_str(msg, &s, &len);
    LOG_I("send cmd catalog: \n%s", s);
    return 0;
}

int cls_sip_client::parse_xml(const char *data, const char *s_mark, bool with_s_make, const char *e_mark, bool with_e_make, char *dest)
{
    const char *satrt = strstr(data, s_mark); // 查找子字符串，返回str2第一次在str1中出现的地址，否则NULL

    if (satrt != NULL)
    {
        const char *end = strstr(satrt, e_mark);
        if (end != NULL)
        {
            int s_pos = with_s_make ? 0 : strlen(s_mark);
            int e_pos = with_e_make ? strlen(e_mark) : 0;

            strncpy(dest, satrt + s_pos, (end + e_pos) - (satrt + s_pos));
        }
        return 0;
    }
    return -1;
}

void cls_sip_client::dump_request(eXosip_event_t *evt)
{
    char *s;
    size_t len;
    osip_message_to_str(evt->request, &s, &len);
    LOG_I("\n打印请求包开始\ntype=%d\n%s\n打印请求包结束\n", evt->type, s);
}

void cls_sip_client::dump_response(eXosip_event_t *evt)
{
    char *s;
    size_t len;
    osip_message_to_str(evt->response, &s, &len);
    LOG_I("\n打印响应包开始\ntype=%d\n%s\n打印响应包结束\n", evt->type, s);
}
